/**
 * @author Peter Kirn peter@createdigitalmedia.net
 * @author Naim Falandino naim@knowlogik.com
 * 
 * @description Service code modeled on Google API examples and Reto Meier AudioTrack implementation
 *              Based on Bad Logic Games' documentation of AudioTrack usage
 *              http://apistudios.com/hosted/marzec/badlogic/wordpress/?p=228
 */

package org.puredata;

import java.util.logging.Logger;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class PdService extends Service {

    private static final String TAG = "PdService";

    private final IBinder mBinder = new PdBinder();

    private int NOTIFICATION_ID = 1;
    private NotificationManager mNM = null;
    private PdAudio pdAudio = null;

    private volatile PlaybackState playbackState = null;

    private static enum PlaybackState {
        PLAY, PAUSE;
    }

    static {
        System.loadLibrary("pdportable");
    }

    @Override
    public void onCreate() {
        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        Log.d(TAG, "Attempting to create PdAudio object");

        pdAudio = new PdAudio();

        Log.d(TAG, "Attempting to start Pd");

        this.startPd();

        // try {
        // Thread.sleep(5000l);
        // } catch (InterruptedException ex) {
        // Log.e(TAG, "Thread was interrupted while wating for Pd to start");
        // }

        // this.pause(); // NOTE Not entirely sure about this: Pd inits in "play" state. Pause until
        // patch is loaded.

        // TODO set thread priority to high (poss. independent from Service
        // priority?)
        /*
         * new Thread(new Runnable() { public void run() { // TODO code just for testing that audio
         * works (DSP in Java != // awesome, but it works) final float frequency = 440; float
         * increment = (float) (2 * Math.PI) * frequency / 44100; // angular // increment // for //
         * each // sample float angle = 0; PdAudio device = new PdAudio(); float samples[] = new
         * float[1024];
         * 
         * while (true) { for (int i = 0; i < samples.length; i++) { samples[i] = (float)
         * Math.sin(angle); angle += increment; }
         * 
         * device.writeSamples(samples); } } }).start();
         */
    }

    @Override
    public void onDestroy() {
        // this.sendMessage("pd", "dsp", "i", 0);
        pdAudio.shutdown();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO (pk) Service binding implementation here
        return mBinder;
    }

    // NOTE (naim) This onStartCommand methods doesn't appear to be getting called because
    // startService(Intent) isn't being called from the Activity. I tried adding
    // startService(getIntent()) to the onResume() method in the Activity and this did indeed start
    // getting called, but it was called twice in a row (not sure why) andd the application crashed
    // unexpectedly after the second call. I'm not knowledgeable enough right now about Anrdoid
    // services to understand why that is, but it's something to keep in mind.
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO: (pk) gracefully handle killing service
        // TODO: (pk) ensure foreground priority is actually working
        // TODO: (pk) verify why this notification isn't appearing

        Notification notification = new Notification(R.drawable.icon,
                getText(R.string.pd_service_start_notification), System.currentTimeMillis());
        startForeground(NOTIFICATION_ID, notification);
        return START_STICKY;
    }

    protected void play() {
        synchronized (this) {
            this.sendMessage("pd", "dsp", "i", 1); // switches on Pd's audio to default output
            pdAudio.play();
            playbackState = PlaybackState.PLAY;
        }
    }

    protected void pause() {
        synchronized (this) {
            this.sendMessage("pd", "dsp", "i", 0); // turns off Pd audio
            pdAudio.pause();
            playbackState = PlaybackState.PAUSE;
        }
    }

    // Native methods for calling Pd
    private native void openPatch(String filename, String directory);

    private native void startPd();

    private native void sendMessage(String receive, String message, String format, int i);

    // Service binder
    public class PdBinder extends Binder {
        PdService getService() {
            return PdService.this;
        }
    }
}
